﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using SEVDNUG.Web.Sitefinity.Tools.DataImporter;
using Telerik.Cms.Engine;
using Telerik.Cms.Web.UI;
using Telerik.Personalization;
using Telerik.RadUploadUtils;
using Telerik.Web;
using Telerik.WebControls;

namespace SEVDNUG.Web.Sitefinity.Tools.DataImporter
{
    /// <summary>
    /// The command panel for the Import Data tool
    /// </summary>
    public class ControlPanel: ControlPanelBase
    {
        #region Private Properties

        private readonly ImportData _customTool;
        private MessageControl _msgControl;
        private Container _container;
        private ITemplate _itemTemplate;
        
        private string _providerName;
        private List<string> _metaKeys;
        private List<string> _filenames;
        private List<string> _fieldNames;
        private BindingList<ImportDataMapping> _mappings;
        
        private const string MAPPINGS  = "Mappings";
        private const string META_KEYS = "MetaKeys";
        private const string FIELD_NAMES = "FieldNames";
        private const string FILE_NAMES = "Filenames";
        private const string PROVIDER_NAME = "ProviderName";
        private const string ITEM_TEMPLATE_PATH = "ItemTemplatePath";
        private const string DEFAULT_ITEM_TEMPLATE_PATH = "~/Sitefinity/Admin/ControlTemplates/Tools/ImportData.ascx";

        #endregion Private Properties

        #region Private Enums

        /// <summary>
        /// Contains a list of wizard steps.
        /// </summary>
        private enum Steps
        {
            /// <summary>
            /// The Provide selection page
            /// </summary>
            SelectProvider,
            /// <summary>
            /// The Import Source selection page
            /// </summary>
            ImportSource,
            /// <summary>
            /// The Meta Data to field mappings page
            /// </summary>
            MetaMappings,
            /// <summary>
            /// The Completion page.
            /// </summary>
            Complete
        }

        #endregion Private Enums

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="ControlPanel"/> class.
        /// </summary>
        /// <param name="customTool">The custom tool that is creating the control panel.</param>
        /// <param name="title">The title of the control panel.</param>
        public ControlPanel(ImportData customTool, string title):base(title)
        {
            this._customTool = customTool;
        }
        #endregion Constructors

        #region ControlPanelBase Implementation
        protected override System.Web.UI.HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
        
        /// <summary>
        /// Creates the Child Controls for this <see cref="ControlPanelBase"/>
        /// </summary>
        protected override void CreateChildControls()
        {

            this.Controls.Clear();
            this._msgControl = new MessageControl();
            this.Controls.Add(this._msgControl);

            // Verify that we have the necessary permissions
            SecurityPermission perm = new SecurityPermission(PermissionState.Unrestricted);
            if (!SecurityManager.IsGranted(perm))
            {
                HtmlGenericControl child = new HtmlGenericControl("div");
                child.Attributes.Add("style", "background:#FFFFE1;padding: 10px 10px 10px 3px;border:1px dashed #999;margin:10px 10px 0 0");
                child.InnerText = "This tool requires unrestricted permissions in order to work properly";
                this.Controls.Add(child);
            }

            // Build the Container
            this._container = new Container(this);
            if ((this._itemTemplate == null) && (this.Page != null))
            {
                string itemTemplatePath = this.ItemTemplatePath;
                if (File.Exists(this.Page.MapPath(itemTemplatePath)))
                {
                    this._itemTemplate = this.Page.LoadTemplate(itemTemplatePath);
                }
                else
                {
                    this._itemTemplate = new DefaultItemTemplate();
                }
            }
            this._itemTemplate.InstantiateIn(this._container);

            // Display the FAQ Divs if the preference is on.
            #region FAQ Divs
            if (this._container.ProviderFAQ != null)
            {
                this._container.ProviderFAQ.Visible = PersonalizationManager.DefaultInstance.GetGlobalValue<bool>("showFaq", true);
            }
            if (this._container.ImportSourceFAQ != null)
            {
                this._container.ImportSourceFAQ.Visible = PersonalizationManager.DefaultInstance.GetGlobalValue<bool>("showFaq", true);
            }
            if (this._container.MetaMappingsFAQ != null)
            {
                this._container.MetaMappingsFAQ.Visible = PersonalizationManager.DefaultInstance.GetGlobalValue<bool>("showFaq", true);
            }
            if (this._container.CompleteFAQ != null)
            {
                this._container.CompleteFAQ.Visible = PersonalizationManager.DefaultInstance.GetGlobalValue<bool>("showFaq", true);
            }
            #endregion FAQ Divs

            this.Controls.Add(this._container);
            
            // Set up all of the events

            // Set up the "next" button events
            this._container.MoveToImportSourceBtn.Click += new EventHandler(moveToImportSourceBtn_Click);
            this._container.MoveToMetaMappingsBtn.Click += new EventHandler(moveToMetaMappingsBtn_Click);
            this._container.StartImportBtn.Click += new EventHandler(startImportBtn_Click);

            // Set up the Meta Key Mappings events
            this._container.JoinButton.Click += new EventHandler(joinButton_Click);
            this._container.MetaMappingsGrid.RowDeleted += new GridViewDeletedEventHandler(metaMappingsGrid_RowDeleted);
            this._container.MetaMappingsGrid.RowDeleting += new GridViewDeleteEventHandler(metaMappingsGrid_RowDeleting);

            // Populate the Controls
            populateProviders();
            populateMetaKeys();
            populateFieldNames();
            bindMappings();

        }

        #endregion ControlPanelBase Implementation

        #region Properties

        public ITemplate ItemTemplate
        {
            get
            {
                return this._itemTemplate;
            }
            set
            {
                this._itemTemplate = value;
            }
        }

        public string ItemTemplatePath
        {
            get
            {
                string str = (string)this.ViewState[ITEM_TEMPLATE_PATH];
                if (!string.IsNullOrEmpty(str))
                {
                    return str;
                }
                return DEFAULT_ITEM_TEMPLATE_PATH;
            }
            set
            {
                this.ViewState[ITEM_TEMPLATE_PATH] = value;
            }
        }

        public BindingList<ImportDataMapping> Mappings
        {
            get
            {
                if (ViewState[MAPPINGS] ==null)
                {
                    _mappings = new BindingList<ImportDataMapping>();   
                }
                else
                {
                    _mappings = (BindingList<ImportDataMapping>) ViewState[MAPPINGS];
                }
                return _mappings;
            }
            set
            {
                this.ViewState[MAPPINGS] = value;
            }
        }

        public List<string> MetaKeys
        {
            get
            {
                if (ViewState[META_KEYS] == null)
                {
                    _metaKeys = new List<string>();
                }
                else
                {
                    _metaKeys = (List<string>)ViewState[META_KEYS];
                }
                return _metaKeys;
            }
            set
            {
                ViewState[META_KEYS] = value;
            }
        }

        public List<string> FieldNames
        {
            get
            {
                if (ViewState[FIELD_NAMES] == null)
                {
                    _fieldNames = new List<string>();
                }
                else
                {
                    _fieldNames = (List<string>) ViewState[FIELD_NAMES];
                }
                return _fieldNames;
            }
            set
            {
                ViewState[FIELD_NAMES] = value;
            }
        }
        
        public List<string> Filenames
        {
            get
            {
                if (ViewState[FILE_NAMES] == null)
                {
                    _filenames = new List<string>();
                }
                else
                {
                    _filenames = (List<string>)ViewState[FILE_NAMES];
                }
                return _filenames;
            }
            set
            {
                ViewState[FILE_NAMES] = value;
            }
        }

        public string ProviderName
        {
            get
            {
                if (ViewState[PROVIDER_NAME] == null)
                {
                    _providerName = "";
                }
                else
                {
                    _providerName = (string)ViewState[PROVIDER_NAME];
                }
                return _providerName;
            }
            set
            {
                ViewState[PROVIDER_NAME] = value;
            }
        }



        #endregion Properties

        #region Private methods

        /// <summary>
        /// Binds the Meta Data field mappings to the Grid
        /// </summary>
        private void bindMappings()
        {
            this._container.MetaMappingsGrid.DataSource = this.Mappings;
            this._container.MetaMappingsGrid.DataBind();
        }

        /// <summary>
        /// Gets a list of Generic Content providers and populates the list. 
        /// </summary>
        private void populateProviders()
        {
            
            ICollection<string> providerList = this._customTool.GetProviders();    

            this._container.ProviderList.Items.Add(new ListItem("-- Default --", ""));
            foreach (string s in providerList)
            {
                this._container.ProviderList.Items.Add(new ListItem(s,s));
            }

            if (this.ProviderName != null)
            {
                this._container.ProviderList.SelectedValue = this.ProviderName;
            }

        }

        /// <summary>
        /// Populates the meta keys.
        /// </summary>
        private void populateMetaKeys()
        {

            IDictionary<string, IMetaInfo> keys = this._customTool.GetMetaKeys(this.ProviderName);
            List<string> metaKeys = new List<string>();

            // Clear the Meta Keys List
            this._container.MetaKeysList.Items.Clear();

            // Populate the Meta Keys
            this._container.MetaKeysList.Items.Add("");
            this._container.MetaKeysList.Items.Add(this._customTool.ContentKey);
            foreach (string key in keys.Keys)
            {
                this._container.MetaKeysList.Items.Add(key);
                metaKeys.Add(key);
            }

            this.MetaKeys = metaKeys;

        }

        /// <summary>
        /// Populates the field names.
        /// </summary>
        private void populateFieldNames()
        {
            if (Filenames.Count > 0)
            {
                FieldNames = this._customTool.GetFieldNames(Filenames[0]);
                FieldNames.Insert(0, "");
                this._container.FieldList.DataSource = FieldNames;
                this._container.FieldList.DataBind();
            }
        }

        /// <summary>
        /// Shows a Success message using the Sitefinity message control.
        /// </summary>
        /// <param name="message">The message to display.</param>
        private void showMessage(string message)
        {
            this._msgControl.Mode = MessageMode.Success;
            this._msgControl.Message = message;
        }

        /// <summary>
        /// Shows an Error message using the Sitefinity message control.
        /// </summary>
        /// <param name="message">The message to display.</param>
        private void showErrorMessage(string message)
        {
            this._msgControl.Mode = MessageMode.Error;
            this._msgControl.Message = message;
        }


        /// <summary>
        /// Gets the uploaded files.
        /// </summary>
        /// <param name="upload">The upload.</param>
        /// <returns>A List&lt;string&gt; of filenames</returns>
        private List<string> getUploadedFiles(RadUpload upload)
        {

            string folder = getUploadFolder(upload);
            List<string> files = new List<string>();
            foreach (UploadedFile file in upload.UploadedFiles)
            {
                string filename = Path.GetFileName(file.FileName);
                files.Add(Path.Combine(folder, filename));
            }

            return files;
        }


        /// <summary>
        /// Gets the upload folder.
        /// </summary>
        /// <param name="upload">The <see cref="RadControl"/> instance.</param>
        /// <returns>The fully qualified server path to the upload directory.</returns>
        private string getUploadFolder(RadUpload upload)
        {
            string folder;
            // Get the folder path
            if (string.IsNullOrEmpty(upload.TargetPhysicalFolder))
            {
                folder = this.Page.Server.MapPath(upload.TargetFolder);
            }
            else
            {
                folder = upload.TargetPhysicalFolder;
            }
            return folder;
        }

        #region Wizard Steps
        /// <summary>
        /// This tasks is responsible for moving the wizard to the next step of 
        /// Import Source.
        /// </summary>
        private void moveToImportSource()
        {
            string providerName = this._container.ProviderList.SelectedValue;
            this.ProviderName = providerName;
            this._container.MetaKeysSourceLbl.Text = string.Format(" [{0}]", providerName);
            populateMetaKeys();
        }

        /// <summary>
        /// This tasks is responsible for moving the wizard to the next step of 
        /// Meta Data Mapping.
        /// </summary>
        private void moveToMetaMapping()
        {

            Filenames = getUploadedFiles(this._container.Uploader);

            if (this._container.Uploader.UploadedFiles.Count > 1)
            {
                showMessage(string.Format(Resources.ImportDataControlPanel.Upload_Multiple,
                                          this._container.Uploader.UploadedFiles.Count));
            }
            else if (this._container.Uploader.UploadedFiles.Count == 0)
            {
                showMessage(Resources.ImportDataControlPanel.Upload_Nothing);
            }
            else
            {
                showMessage(string.Format(Resources.ImportDataControlPanel.Upload_Success, Filenames[0]));
                this._container.FieldListSourceLbl.Text = string.Format(" [{0}]", System.IO.Path.GetFileName(Filenames[0]));
                populateFieldNames();
            }

            this._container.MultiPage.SelectedIndex = (int)Steps.MetaMappings;
        }

        /// <summary>
        /// This tasks is responsible for moving the wizard to the next step of 
        /// Start Import.
        /// </summary>
        private void startImport()
        {
            Results results = this._customTool.Import(this.Mappings, this.ProviderName, this.Filenames);
            this._container.TotalRecordsFailedLbl.Text = results.TotalFailedRecords.ToString();
            this._container.TotalRecordsImportedLbl.Text = results.TotalImportedRecords.ToString();
            this._container.TotalRecordsLbl.Text = results.TotalRecords.ToString();

            if (results.TotalFailedRecords > 0)
            {
                string temp = results.TotalFailedRecords > 1 ? Resources.ImportDataControlPanel.Import_Failed : Resources.ImportDataControlPanel.Import_Failed_Single;
                showErrorMessage(string.Format(temp, results.TotalFailedRecords));
            }
            else
            {
                string temp = results.TotalRecords > 1 ? Resources.ImportDataControlPanel.Import_Success : Resources.ImportDataControlPanel.Import_Success_Single;
                showMessage(string.Format(temp, results.TotalRecords));
            }

            // Show the exceptions if the grid is present
            if (this._container.ExceptionsGrid != null)
            {
                this._container.ExceptionsGrid.DataSource = results.ImportExceptions;
                this._container.ExceptionsGrid.DataBind();
            }

        }
        #endregion Wizard Steps

        #endregion Private methods

        #region Events

        #region Wizard Steps [Events]

        // Step 1 -> 2
        void moveToImportSourceBtn_Click(object sender, EventArgs e)
        {

            moveToImportSource();
            this._container.MultiPage.SelectedIndex = (int)Steps.ImportSource;
        }

        // Step 2 -> 3 
        void moveToMetaMappingsBtn_Click(object sender, EventArgs e)
        {
            try
            {
                if (this._container.Uploader.UploadedFiles.Count > 0)
                {
                    moveToMetaMapping();
                }
                else
                {
                  showErrorMessage(Resources.ImportDataControlPanel.Upload_Nothing);
                }
            }
            catch (Exception ex)
            {
                showErrorMessage(ex.Message);
            }
            
        }

        // Step 3 -> 4 
        void startImportBtn_Click(object sender, EventArgs e)
        {
            startImport();
            this._container.MultiPage.SelectedIndex = (int)Steps.Complete;
        }
        #endregion Wizards Steps [Events]

        void joinButton_Click(object sender, EventArgs e)
        {
            showMessage("");
            ImportDataMapping mapping = new ImportDataMapping
                                            {
                                                FieldName = this._container.FieldList.SelectedValue,
                                                FixedValue = this._container.FixedValue.Text,
                                                MetaKey = this._container.MetaKeysList.SelectedValue
                                            };
            _mappings = Mappings;
            _mappings.Add(mapping);
            Mappings = _mappings;

            bindMappings();
            
        }
        
        void metaMappingsGrid_RowDeleted(object sender, GridViewDeletedEventArgs e)
        {
            // Display whether the delete operation succeeded.
            if (e.Exception == null)
            {
                showMessage(Resources.ImportDataControlPanel.rowDeletionSuccess);
            }
            else
            {
                showErrorMessage(Resources.ImportDataControlPanel.rowDeletionError);
                e.ExceptionHandled = true;
            }
            

        }

        void metaMappingsGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            try
            {
                _mappings.RemoveAt(e.RowIndex);
                bindMappings();
            }
            catch
            {
                e.Cancel = true;
            }
        }

        #endregion Events

        private class Container: GenericContainer<ControlPanel>
        {

            private bool _loadedControls;

            private RadMultiPage _multiPage;

            // Step 1: Controls
            private DropDownList _providerList;
            private LinkButton _moveToImportSourceBtn;

            // Step 2: Controls
            private RadUpload _uploader;
            private LinkButton _moveToMetaMappingsBtn;

            // Step 3: Controls
            private DropDownList _metaKeysList;
            private Button _joinButton;
            private DropDownList _fieldList;
            private ITextControl _fixedValue;
            private GridView _metaMappingsGrid;
            private LinkButton _startImportBtn;
            private Label _metaKeysSourceLbl;
            private Label _fieldListSourceLbl;

            // Step 4: Controls
            private Label _totalRecordsLbl;
            private Label _totalRecordsImportedLbl;
            private Label _totalRecordsFailedLbl;
            // optional
            private GridView _exceptionsGrid;

            // Optional Controls
            // FAQ Divs
            private HtmlGenericControl _providerFAQ;
            private HtmlGenericControl _importSourceFAQ;
            private HtmlGenericControl _metaMappingsFAQ;
            private HtmlGenericControl _completeFAQ;
            
            public Container(ControlPanel owner) : base(owner)
            {
                
            }

            private void loadControls()
            {
                if (!this._loadedControls)
                {
                    this._multiPage = (RadMultiPage) base.FindControl(typeof (RadMultiPage), "multiPage", true);

                    // Step 1: Select Generic Provider
                    this._providerList = (DropDownList)base.FindControl(typeof(DropDownList), "ddlProviderList", true);
                    this._moveToImportSourceBtn =
                        (LinkButton) base.FindControl(typeof (LinkButton), "btnMoveToImportSource", true);

                    // Step 2: Select Import Source
                    this._uploader = (RadUpload) base.FindControl(typeof (RadUpload), "uploader", true);
                    this._moveToMetaMappingsBtn =
                        (LinkButton) base.FindControl(typeof (LinkButton), "btnMoveToMetaMappings", true);

                    // Step 3: Map Meta fields
                    this._metaKeysList = (DropDownList)base.FindControl(typeof(DropDownList), "ddlMetaKeysList", true);
                    this._joinButton = (Button)base.FindControl(typeof(Button), "btnJoin", true);
                    this._fieldList = (DropDownList)base.FindControl(typeof(DropDownList), "ddlFieldList", true);
                    this._fixedValue = (ITextControl) base.FindControl(typeof(ITextControl),"txtFixedValue", true);
                    this._metaMappingsGrid = (GridView)base.FindControl(typeof(GridView), "grdMetaMappings", true);
                    this._startImportBtn = (LinkButton) base.FindControl(typeof (LinkButton), "btnStartImport", true);
                    this._metaKeysSourceLbl = (Label)base.FindControl(typeof(Label), "lblMetaKeysListSource", true);
                    this._fieldListSourceLbl = (Label)base.FindControl(typeof(Label), "lblFieldListSource", true);

                    // Step 4 Complete
                    this._totalRecordsLbl = (Label) base.FindControl(typeof (Label), "lblTotalRecords", true);
                    this._totalRecordsImportedLbl = (Label)base.FindControl(typeof(Label), "lblTotalRecordsImported", true);
                    this._totalRecordsFailedLbl = (Label)base.FindControl(typeof(Label), "lblTotalRecordsFailed", true);
                    // Optional
                    this._exceptionsGrid = (GridView) base.FindOptionalControl<GridView>("grdExceptions");

                    // Optional FAQ divs
                    this._providerFAQ = base.FindOptionalControl<HtmlGenericControl>("divProviderFAQ");
                    this._importSourceFAQ = base.FindOptionalControl<HtmlGenericControl>("divImportSourceFAQ");
                    this._metaMappingsFAQ = base.FindOptionalControl<HtmlGenericControl>("divMetaMappingsFAQ");
                    this._completeFAQ = base.FindOptionalControl<HtmlGenericControl>("divCompleteFAQ");

                    this._loadedControls = true;
                }
            }

            #region Required Controls

            public RadMultiPage MultiPage
            {
                get
                {
                    loadControls();
                    return this._multiPage;
                }
            }

            #region Step 1
            public DropDownList ProviderList
            {
                get
                {
                    this.loadControls();
                    return this._providerList;
                }
            }
            public LinkButton MoveToImportSourceBtn
            {
                get
                {
                    this.loadControls();
                    return this._moveToImportSourceBtn;
                }
            }
            #endregion Step 1

            #region Step 2

            public RadUpload Uploader
            {
                get
                {
                    this.loadControls();
                    return this._uploader;
                }
            }

            public LinkButton MoveToMetaMappingsBtn
            {
                get
                {
                    this.loadControls();
                    return this._moveToMetaMappingsBtn;
                }
            }
            #endregion Step 2

            #region Step 3

            public DropDownList MetaKeysList
            {
                get
                {
                    this.loadControls();
                    return this._metaKeysList;
                }
            }

            public Button JoinButton
            {
                get
                {
                    this.loadControls();
                    return this._joinButton;
                }
            }

            public DropDownList FieldList
            {
                get
                {
                    this.loadControls();
                    return this._fieldList;
                }
            }

            public ITextControl FixedValue
            {
                get
                {
                    loadControls();
                    return this._fixedValue;
                }
            }

            public GridView MetaMappingsGrid
            {
                get
                {
                    this.loadControls();
                    return this._metaMappingsGrid;
                }
            }

            public LinkButton StartImportBtn
            {
                get
                {
                    this.loadControls();
                    return this._startImportBtn;
                }
            }
            public Label MetaKeysSourceLbl
            {
                get
                {
                    this.loadControls();
                    return this._metaKeysSourceLbl;
                }
            }
            public Label FieldListSourceLbl
            {
                get
                {
                    this.loadControls();
                    return this._fieldListSourceLbl;
                }
            }
            #endregion Step 3

            #region Step 4

            public Label TotalRecordsLbl
            {
                get
                {
                    loadControls();
                    return this._totalRecordsLbl;
                }
            }

            public Label TotalRecordsImportedLbl
            {
                get
                {
                    loadControls();
                    return this._totalRecordsImportedLbl;
                }
            }

            public Label TotalRecordsFailedLbl
            {
                get
                {
                    loadControls();
                    return this._totalRecordsFailedLbl;
                }
            }

            public GridView ExceptionsGrid
            {
                get
                {
                    loadControls();
                    return this._exceptionsGrid;
                }
            }
            #endregion Step 4

            #endregion Required Controls

            #region Optional Controls

            #region FAQs
            public HtmlGenericControl ProviderFAQ
            {
                get
                {
                    this.loadControls();
                    return this._providerFAQ;
                }
            }
            public HtmlGenericControl ImportSourceFAQ
            {
                get
                {
                    this.loadControls();
                    return this._importSourceFAQ;
                }
            }
            public HtmlGenericControl MetaMappingsFAQ
            {
                get
                {
                    this.loadControls();
                    return this._metaMappingsFAQ;
                }
            }
            public HtmlGenericControl CompleteFAQ
            {
                get
                {
                    this.loadControls();
                    return this._completeFAQ;
                }
            }
            #endregion FAQs

            #endregion Optional Controls

        }

        private class DefaultItemTemplate : ITemplate
        {
            public void InstantiateIn(Control container)
            {
                
            }
        }
    }


}
